package com.hexseek.libretvcloud.service;

import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hexseek.libretvcloud.exception.CustomException;
import com.hexseek.libretvcloud.model.Proxy;
import com.hexseek.libretvcloud.model.SearchResponse;
import com.hexseek.libretvcloud.model.SearchResult;
import com.hexseek.libretvcloud.utils.HttpRequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SearchService {

    @Autowired
    private HttpRequestUtils httpRequestUtils;

    @Autowired
    private ProxyService proxyService;

    @Autowired
    private ExecutorService executorService;

    @Value("${proxy.search.path}")
    private String searchPath;

    /**
     * 使用SSE流式返回搜索结果
     */
    public SseEmitter searchStream(String userId, String query, int page) {
        SseEmitter emitter = new SseEmitter(60_000L); // 60秒超时

        // 设置SSE完成、超时和错误的回调
        emitter.onCompletion(() -> log.info("SSE连接完成: {}", userId));
        emitter.onTimeout(() -> {
            log.info("SSE连接超时: {}", userId);
            emitter.complete();
        });
        emitter.onError(e -> {
            log.error("SSE连接错误: {}", userId, e);
            emitter.completeWithError(e);
        });

        executorService.execute(() -> {
            try {
                // 获取所有启用的API源
                List<Proxy> sourceList = getProxySources(userId);

                if (ObjectUtil.isEmpty(sourceList)) {
                    emitter.complete();
                    return;
                }

                // 并行搜索各个API源
                List<CompletableFuture<Void>> futures = sourceList.stream()
                        .map(source -> CompletableFuture.runAsync(() ->
                                streamSearchResults(emitter, userId, query, source, page), executorService))
                        .collect(Collectors.toList());

                // 等待所有任务完成
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                        .thenRun(emitter::complete)
                        .exceptionally(ex -> {
                            log.error("搜索任务异常: {}", ex.getMessage());
                            emitter.completeWithError(ex);
                            return null;
                        });
            } catch (Exception e) {
                log.error("搜索过程异常: {}", e.getMessage());
                emitter.completeWithError(e);
            }
        });

        return emitter;
    }

    private List<Proxy> getProxySources(String userId) {
        List<Proxy> defaultProxy = proxyService.getDefaultProxy();
        List<Proxy> customProxy = proxyService.getCustomProxy(userId);
        List<Proxy> sourceList = new ArrayList<>();
        sourceList.addAll(defaultProxy);
        sourceList.addAll(customProxy);
        return sourceList;
    }

    private void streamSearchResults(SseEmitter emitter, String userId, String query, Proxy source, int page) {
        try {
            SearchResponse pageResponse = fetchPage(source, query, page);
            sendResults(emitter, convertToSearchResults(userId, query, source.getProxyId(), pageResponse.getList(), source.getName()));
        } catch (Exception e) {
            log.error("API {} 搜索失败: {}", source.getProxyId(), e.getMessage());
            // 发生异常时不中断整个搜索，继续处理其他源
        }
    }

    private void sendResults(SseEmitter emitter, List<SearchResult> results) {
        results.forEach(result -> {
            try {
                // 逐个发送搜索结果，提高实时性
                emitter.send(SseEmitter.event()
                        .id(UUID.randomUUID().toString())
                        .name("searchResult")
                        .data(result));
            } catch (IOException e) {
                throw new RuntimeException("SSE发送失败", e);
            }
        });
    }

    private SearchResponse fetchPage(Proxy source, String query, int page) throws JsonProcessingException {
        String url = source.getApiUrl() + searchPath
                .replace("{query}", query)
                .replace("{page}", String.valueOf(page));

        String responseBody = httpRequestUtils.get(url);
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.readValue(responseBody, SearchResponse.class);
    }

    private List<SearchResult> convertToSearchResults(String userId, String query, long proxyId,
                                                      List<Map<String, Object>> items, String sourceName) {
        if (items == null) {
            return Collections.emptyList();
        }

        return items.stream()
                .map(item -> {
                    SearchResult result = new SearchResult();
                    result.setUserId(userId);
                    result.setKeyword(query);
                    result.setProxyId(String.valueOf(proxyId));
                    result.setVodId(String.valueOf(item.getOrDefault("vod_id", "")));
                    result.setVodName(String.valueOf(item.getOrDefault("vod_name", "")));
                    result.setVodPic(String.valueOf(item.getOrDefault("vod_pic", "")));
                    result.setTypeName(String.valueOf(item.getOrDefault("type_name", "")));
                    result.setVodYear(String.valueOf(item.getOrDefault("vod_year", "")));
                    result.setVodRemarks(String.valueOf(item.getOrDefault("vod_remarks", "")));
                    result.setProxyName(sourceName); // 添加源名称
                    return result;
                })
                .collect(Collectors.toList());
    }

    public void shutdown() {
        executorService.shutdown();
        try {
            if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
                executorService.shutdownNow();
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
        }
    }
}